﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

using CSJ2K.Util;
using CSJ2K.Util.IO;
using CSJ2K.Jp2.Boxes;

namespace CSJ2K.Jp2
{
    public abstract class Box
    {
        public enum BoxTypes : uint
        {
            // JP2 Box Types
            jp00=0x6A502020,    // File Signature
            ftyp=0x66747970,    // File Type
            jp2h=0x6A703268,    // JP2 Header
            ihdr=0x69686472,    // Image Header
            bpcc=0x62706363,    // Bits Per Component
            colr=0x636F6C72,    // Color Specification
            pclr=0x70636C72,    // Palette
            cmap=0x636D6170,    // Component Mapping
            cdef=0x63646566,    // Channel Definition
            res0=0x72657320,    // Resolution
            resc=0x72657363,    // Capture Resolution
            resd=0x72657364,    // Default Display Resolution
            jp2c=0x6A703263,    // Contiguous Codestream
            jp2i=0x6A703269,    // Intellectual Property
            xml0=0x786D6C20,    // XML
            uuid=0x75756964,    // UUID
            uinf=0x75696E66,    // UUID Info
            ulst=0x75637374,    // UUID List
            url0=0x75726C20,    // URL

            // JPX Box Types
            asoc=0x61736F63,    // Association
            bfil=0x6266696C,    // Binary Filter
            cgrp=0x63677270,    // Color Group
            chck=0x6368636B,    // Digital Signature
            comp=0x636F6D70,    // Composition
            copt=0x636F7074,    // Composition Options
            cref=0x63726566,    // Cross-Reference
            creg=0x63726567,    // Codestream Registration
            drep=0x64726570,    // Desired Reproductions
            dtlb=0x6474626C,    // Data Reference
            flst=0x666C7374,    // Fragment List
            free=0x66726565,    // Free
            ftbl=0x6674626C,    // Fragment Table
            gtso=0x6774736F,    // Graphics Technology Standard Output
            inst=0x696E7374,    // Instruction Set
            jpch=0x6A706368,    // Codestream Header
            jplh=0x6A706C68,    // Compositing Layer Header
            lbl0=0x6C626C20,    // Label
            mdat=0x6D646174,    // Media Data
            mp7b=0x6D703762,    // MPEG-7 Binary
            nlst=0x6E6C7374,    // Number List
            opct=0x6F706374,    // Opacity
            roid=0x726F6964,    // ROI Description
            rreq=0x72726571,    // Resource Requirements
        }

        public long Start { get; set; }
        public long ContentStart { get; set; }

        public uint Length { get; set; }
        public ulong ExtendedLength { get; set; }
        public BoxTypes Type { get; set; }

        public Box(Stream source, long start, uint length, BoxTypes type, ulong extendedLength)
        {
            Start = start;
            Length = length;
            Type = type;
            ExtendedLength = extendedLength;
            ContentStart = source.Position;
        }

        public static Box FromStream(Stream source)
        {
            long start = source.Position;
            uint length = StreamUtil.ReadBUInt32(source);
            return FromStream(source, start, length);
        }

        public static Box FromStream(Stream source, long start, uint length)
        {
            ulong extendedLength = 0;
            if (length == 1) extendedLength = StreamUtil.ReadBUInt64(source);
            BoxTypes type = (BoxTypes)StreamUtil.ReadBUInt32(source);

            if (DEBUG.Jp2File) Debug.WriteLine("Box " + type.ToString() + " Length " + length + " Extended Length " + extendedLength);
            switch (type)
            {
                case BoxTypes.jp2c:
                    return new Jp2cBox(source, start, length, type, extendedLength);
                default:
                    return new UnsupportedBox(source, start, length, type, extendedLength);
            }
        }
    }
}
